/*! \file OrbitFunctors.h
 *	\brief <write description for OrbitFunctors.h>
 *
 *	created:	2010/09/08
 *	created:	8:9:2010   12:11
 *	filename: 	s:\DNG-Code\Kiev\Modules\Orbit\Protection\Include\OrbitFunctors.h
 *	file path:	s:\DNG-Code\Kiev\Modules\Orbit\Protection\Include
 *	file base:	OrbitFunctors
 *	file ext:	h
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */

#ifndef _protection_ORBITFUNCTORS_H_
#define _protection_ORBITFUNCTORS_H_

#pragma once

#include "assert.h"

// This is derived from Rich Hickey's free callback library.
// the original notice as well as the documentation is below.

// 06/06 James Therien
// Major revision. 
// -Changed MakeFunctor to use member template functions. No more dummy arguments.
// Now use (functor-type)::MakeFunctor();
// -Collapsed all the code within the functor classes.
// -Removed all the compiler workarounds.
// -Use manual copies
// -Added the possibility to call on a specific target. Use at your own risks.

//**************** callback.hpp **********************
// Copyright 1994 Rich Hickey
/* Permission to use, copy, modify, distribute and sell this software
* for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation.  Rich Hickey makes no
* representations about the suitability of this software for any
* purpose.  It is provided "as is" without express or implied warranty.
*/


// 08/31/96 Rich Hickey
// Added ==, != and <
//  They are not inline, source is in file callback.cpp
//  Note: You must compile and link in callback.obj if you use them
// C++ doesn't allow ptr-to-func to void * anymore -> changed to void (*)(void)
// Added compiler workarounds for MS VC++ 4.2
// Prefixed all macros with RHCB
// Note: derivation from FunctorBase is now public, and access functions
// (for func, target etc) are provided >>for implementation use only<<

// 06/12/94 Rich Hickey
// 3rd major revision
// Now functors are concrete classes, and should be held by value
// Virtual function mechanism removed
// Generic MakeFunctor() mechanism added for building functors
// from both stand-alone functions and object/ptr-to-mem-func pairs


/*
To use:

If you wish to build a component that provides/needs a callback, simply
specify and hold a Functor of the type corresponding to the args
you wish to pass and the return value you need. There are 10 Functors
from which to choose:

Functor0
Functor1<P1>
Functor2<P1,P2>
Functor3<P1,P2,P3>
Functor4<P1,P2,P3,P4>
Functor0wRet<RT>
Functor1wRet<P1,RT>
Functor2wRet<P1,P2,RT>
Functor3wRet<P1,P2,P3,RT>
Functor4wRet<P1,P2,P3,P4,RT>

These are parameterized by their args and return value if any. Each has
a default ctor and an operator() with the corresponding signature.

They can be treated and used just like ptr-to-functions.

If you want to be a client of a component that uses callbacks, you
create a Functor by calling MakeFunctor().

There are three flavors of MakeFunctor - you can create a functor from:

a ptr-to-stand-alone function
an object and a pointer-to-member function.
a pointer-to-member function (which will be called on first arg of functor)

Note: this last was not covered in the article - see CBEXAM3.CPP

The current iteration of this library requires you pass MakeFunctor()
a dummy first argument of type ptr-to-the-Functor-type-you-want-to-create.
Simply cast 0 to provide this argument:

(target-functor-type)::MakeFunctor(ptr-to-function)
(target-functor-type)::MakeFunctor(reference-to-object,ptr-to-member-function)
(target-functor-type)::MakeFunctor(ptr-to-member-function)

The functor system is 100% type safe. It is also type flexible. You can
build a functor out of a function that is 'type compatible' with the
target functor - it need not have an exactly matching signature. By
type compatible I mean a function with the same number of arguments, of
types reachable from the functor's argument types by implicit conversion.
The return type of the function must be implicitly convertible to the
return type of the functor. A functor with no return can be built from a
function with a return - the return value is simply ignored.
(See ethel example below)

All the correct virtual function behavior is preserved. (see ricky
example below).

If you somehow try to create something in violation
of the type system you will get a compile-time or template-instantiation-
time error.

The Functor base class and translator
classes are artifacts of this implementation. You should not write
code that relies upon their existence. Nor should you rely on the return
value of MakeFunctor being anything in particular.

All that is guaranteed is that the Functor classes have a default ctor,
a ctor that can accept 0 as an initializer,
an operator() with the requested argument types and return type, an
operator that will allow it to be evaluated in a conditional (with
'true' meaning the functor is set, 'false' meaning it is not), and that
Functors can be constructed from the result of MakeFunctor(), given
you've passed something compatible to MakeFunctor(). In addition you
can compare 2 functors with ==, !=, and <. 2 functors with the same
'target' (function, object and/or ptr-to-mem-func) shall compare
equal. op < forms an ordering relation across all target types -> the
actual order is not meaningful or to be depended upon.

/////////////////////// BEGIN Example 1 //////////////////////////
#include <iostream.h>
#include "functors.h"

//do5Times() is a function that takes a functor and invokes it 5 times

void do5Times(const Functor1<int> &doIt)
{
	for(int i=0;i<5;i++)
		doIt(i);
}

//Here are some standalone functions

void fred(int i){cout << "fred: " << i<<endl;}
int ethel(long l){cout << "ethel: " << l<<endl;return l;}

//Here is a class with a virtual function, and a derived class

class B
{
public:
	virtual void ricky(int i){ cout << "B::ricky: " << i<<endl; }
};

class D : public B
{
public:
	virtual void ricky(int i) {cout << "D::ricky: " << i<<endl;}
};

void main()
{
	Functor1<int> ftor;	//a functor variable
	//make a functor from ptr-to-function
	ftor = Functor1<int>::MakeFunctor(fred);

	do5Times(ftor);

	//note ethel is not an exact match - ok, is compatible
	ftor = Functor1<int>::MakeFunctor(ethel);
	do5Times(ftor);

	//create a D object to be a callback target
	D myD;

	//make functor from object and ptr-to-member-func
	ftor = Functor1<int>::MakeFunctor(&myD,&B::ricky);
	do5Times(ftor);
}
/////////////////////// END of example 1 //////////////////////////

/////////////////////// BEGIN Example 2 //////////////////////////
#include <iostream.h>
#include "functors.h"

//Button is a component that provides a functor-based
//callback mechanism, so you can wire it up to whatever you wish

class Button{
public:
//ctor takes a functor and stores it away in a member

	Button(const Functor0 &uponClickDoThis):notify(uponClickDoThis)
	{
	}

	void click()
	{
		//invoke the functor, thus calling back client
		notify();
	}

private:
	//note this is a data member with a verb for a name - matches its
	//function-like usage
	Functor0 notify;
};

class CDPlayer
{
public:
	void play()
		{cout << "Playing"<<endl;}

	void stop()
		{cout << "Stopped"<<endl;}
};

void main()
{
	CDPlayer myCD;
	Button playButton(Functor0::MakeFunctor(&myCD,&CDPlayer::play));
	Button stopButton(Functor0::MakeFunctor(&myCD,&CDPlayer::stop));
	playButton.click();	//calls myCD.play()
	stopButton.click();  //calls myCD.stop()
}
/////////////////////// END of example 2 //////////////////////////

*/

//******************************************************************
///////////////////////////////////////////////////////////////////*
//WARNING - no need to read past this point, lest confusion ensue. *
//Only the curious need explore further - but remember             *
//about that cat!                                                  *
///////////////////////////////////////////////////////////////////*
//******************************************************************

////////////////////////////// THE CODE //////////////////////////

#include <stddef.h> //for size_t

namespace tt{
namespace core{

//typeless representation of a function and optional object
class DummyClassWithVirtualFunc
{
    virtual ~DummyClassWithVirtualFunc() {};
    virtual void Func() = 0;
};

class FunctorBase
{
public:
    //Note: ctors are protected

    //for evaluation in conditionals - can the functor be called?
    operator bool()const{return target||func;}

    //Now you can put them in containers _and_ remove them!
    //Source for these 3 is in callback.cpp
    friend bool operator==(const FunctorBase &lhs,const FunctorBase &rhs);
    friend bool operator!=(const FunctorBase &lhs,const FunctorBase &rhs);
    friend bool operator<(const FunctorBase &lhs,const FunctorBase &rhs);

	//The rest below for implementation use only !

    typedef void (*PFunc)();
    typedef void (DummyClassWithVirtualFunc::*PMemFunc)();

    enum 
    {
        // hardcoding to size 8 so that it works on win32 and PS3; PMemFunc is only 4 bytes, probably smaller because it is virtual (offset in a vtable instead of full function address)
        MEM_FUNC_SIZE = 8 // = sizeof(PMemFunc)  
    };

    PFunc			getFunc() const		{ return func; }
    void*			getTarget() const	{ return target; }
    const char*	    getMemFunc() const	{ return memFunc; }

protected:
    ////////////////////////////////////////////////////////////////
    // Note: this code depends on all ptr-to-mem-funcs being same size
    // If that is not the case then make memFunc as large as largest
    ////////////////////////////////////////////////////////////////
    union
    {
        PFunc func;
        char memFunc[MEM_FUNC_SIZE];
    };

    void *target;

    FunctorBase()
        : func(NULL), target(NULL)
    {
    }

    FunctorBase(const void *c, PFunc f, const void *mf, size_t sz)
        : target((void*)c)
    {
        if (mf)	//must be target/memfunc
        {
//            TT_ASSERTWithMsg(sz <= MEM_FUNC_SIZE, "Ptr to function size is bigger than expected.");

            char* mfcast = (char*)mf;

            for (size_t i = 0; i < sz; ++i)
            {
                memFunc[i] = mfcast[i];
            }
        }
        else	//must be ptr-to-func
        {
            func = f;
        }
    }
};

/************************* no arg - no return *******************/
class Functor0 : public FunctorBase
{
public:

    Functor0() : m_thunk(0) { }
    ~Functor0() { m_thunk = 0;}

    void Call() const
    {
		ttAssert(m_thunk && "Functor::trunk is NULL!!!");
        m_thunk(*this, getTarget());
    }


	template<class Target>
	void Call(Target* t)
	{
		ttAssert(m_thunk && "Functor::trunk is NULL!!!");
		m_thunk(*this, t);
	}

	void operator()() const
	{
		ttAssert(m_thunk && "Functor::trunk is NULL!!!");
		Call();
	}

    // Warning, Using this function is not completely safe, 
	// you have to ensure yourself Target is _exactly_ the same type
	// as the one used with the MakeFunctor call
    template<class Target> 
	void Call(Target* t) const
    {
		ttAssert(m_thunk && "Functor::trunk is NULL!!!");
        m_thunk(*this, t);
    }

    template <class Target, class MemFunc>
    static Functor0 MakeFunctor(Target *t,const MemFunc &m)
    {
        return Functor0(thunk_member<Target, MemFunc>, t, NULL, &m, sizeof(MemFunc));
    }

    template <class Func>
    static Functor0 MakeFunctor(Func f)
    {
        return Functor0(thunk_func<Func>, NULL, (PFunc)f, NULL, NULL);
    }

    void Reset()
    {
        m_thunk = 0;
    }

protected:
    static inline void EmptyFunction() {}

    template <class Func>
    static void thunk_func(const FunctorBase& ftor, void* /*voidTarget*/)
    {
        (Func(ftor.getFunc()))();
    }

    template <class Target, class MemFunc>
    static void thunk_member(const FunctorBase& ftor, void* voidTarget)
    {
        //ttAssert(voidTarget);
        Target *target = (Target *)voidTarget;
        MemFunc &memFunc = (*(MemFunc*)(void*)(ftor.getMemFunc()));
        (target->*memFunc)();
    }

    typedef void (*Thunk)(const FunctorBase &, void* target);

    Functor0(Thunk t, const void *c,PFunc f,const void *mf,size_t sz)
    : FunctorBase(c,f,mf,sz)
	, m_thunk(t) 
    { 
    }

private:
    volatile Thunk m_thunk;
};


/************************* no arg - with return *******************/
template <class RT> class Functor0wRet : public FunctorBase
{
public:
	Functor0wRet() {}

    RT Call()const
    {
        return (thunk(*this, getTarget()));
    }

    template<class Target> 
    RT Call(Target* t) const
    {
        return (thunk(*this, t));
    }

	RT operator()()const
	{
		return Call();
	}

    template <class Func>
    static Functor0wRet<RT> MakeFunctor(Func f)
    {
        return Functor0wRet<RT>(thunk_func<Func>, NULL,(PFunc)f, NULL, NULL);
    }

    template <class Target, class MemFunc>
    static Functor0wRet<RT>  MakeFunctor(Target *t,const MemFunc &m)
    {
        return Functor0wRet<RT>(thunk_member<Target, MemFunc>, t, NULL, &m , sizeof(MemFunc));
    }

protected:

    template <class Func>
    static RT thunk_func(const FunctorBase &ftor, void* target)
    {
        return (Func(ftor.getFunc()))();
    }

    template <class Target, class MemFunc>
    static RT thunk_member(const FunctorBase &ftor, void* t)
    {
        Target *target = (Target *)t;
        MemFunc &memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
        return ((target->*memFunc)());
    }

    typedef RT (*Thunk)(const FunctorBase &, void* target);

    Functor0wRet(Thunk t, const void *c,PFunc f,const void *mf,size_t sz)
        : FunctorBase(c,f,mf,sz),
        thunk(t)
    {
    }

private:
    Thunk thunk;
};


/************************* one arg - no return *******************/
template <class P1>
class Functor1 : public FunctorBase
{
public:
	typedef P1 Arg1;

	Functor1() {}

	void Call(P1 p1)const
	{
		thunk(*this, getTarget(), p1);
	}

	void operator()(P1 p1)const
	{
		Call(p1);
	}

	// Warning: Unsafe
	template<class Target>
	void Call(Target* t, P1 p1) const
	{
		thunk(*this, t, p1);
	}

	//for STL
	typedef P1 argument_type;
	typedef void result_type;

	template <class Target, class MemFunc>
	static Functor1<P1> MakeFunctor(Target* t, const MemFunc &m)
	{
		return Functor1<P1>(thunk_member<Target, MemFunc>, t, NULL, &m, sizeof(MemFunc));
	}

	template <class Func>
	static Functor1<P1> MakeFunctor(Func f)
	{
		return Functor1<P1>(thunk_func<Func>, NULL, (PFunc)f, NULL, NULL);
	}

protected:

	template <class Target, class MemFunc>
	static void thunk_member(const FunctorBase &ftor, void* c, P1 p1)
	{
		Target *target = (Target*)c;
		MemFunc &memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
		(target->*memFunc)(p1);
	}

	template <class Func>
	static void thunk_func(const FunctorBase &ftor, void*, P1 p1)
	{   
		(Func(ftor.getFunc()))(p1);
	}

	typedef void (*Thunk)(const FunctorBase&, void* target, P1);

	Functor1(Thunk t, const void *c, PFunc f, const void *mf,size_t sz)
		: FunctorBase(c,f,mf,sz),
		  thunk(t)
	{
	}

private:
	Thunk thunk;
};


/************************* one arg - with return *******************/
template <class P1,class RT>
class Functor1wRet : public FunctorBase
{
public:
	typedef P1 Arg1;

	Functor1wRet() {}

	RT Call(P1 p1) const
	{
		return (thunk(*this, getTarget(), p1));
	}

	RT operator()(P1 p1)const
	{
		return Call(p1);
	}

	// Unsafe
	template<class Target>
	RT Call(Target* t, P1 p1) const
	{
		return (thunk(*this, t, p1));
	}

	//for STL
	typedef P1 argument_type;
	typedef RT result_type;

	template <class Target, class MemFunc>
	static Functor1wRet<P1, RT> MakeFunctor(Target* c, const MemFunc& m)
	{
		return Functor1wRet<P1,RT>(thunk_member<Target, MemFunc>,c,0,&m,sizeof(MemFunc));
	}

	template <class Func>
	static Functor1wRet<P1, RT> MakeFunctor(Func f)
	{
		return Functor1wRet<P1,RT>(thunk_func<Func>,0,(PFunc)f,0,0);
	}

protected:

	template <class Target, class MemFunc>
	static RT thunk_member(const FunctorBase &ftor, void* t, P1 p1)
	{
		Target *target = (Target *)t;
		MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
		return ((target->*memFunc)(p1));
	}	

	template <class Func>
	static RT thunk_func(const FunctorBase &ftor, void* t, P1 p1)
	{
		return (Func(ftor.getFunc()))(p1);
	}
	
	typedef RT (*Thunk)(const FunctorBase &, void* t, P1);

	Functor1wRet(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
		: FunctorBase(c,f,mf,sz),
		  thunk(t)
	{
	}

private:
	Thunk thunk;
};

/************************* two args - no return *******************/
template <class P1, class P2>
class Functor2 : public FunctorBase
{
public:
	typedef P1 Arg1;
	typedef P2 Arg2;

	Functor2() {}

	void Call(P1 p1, P2 p2)const
	{
		thunk(*this, getTarget(), p1, p2);
	}

	void operator()(P1 p1, P2 p2)const
	{
		Call(p1, p2);
	}

	// Warning: Unsafe
	template<class Target>
	void Call(Target* t, P1 p1, P2 p2) const
	{
		thunk(*this, t, p1, p2);
	}

	//for STL
	typedef P1 first_argument_type;
    typedef P2 second_argument_type;
	typedef void result_type;

	template <class Target, class MemFunc>
	static Functor2<P1,P2> MakeFunctor(Target* t, const MemFunc &m)
	{
		return Functor2<P1,P2>(thunk_member<Target, MemFunc>, t, NULL, &m, sizeof(MemFunc));
	}

	template <class Func>
	static Functor2<P1,P2> MakeFunctor(Func f)
	{
		return Functor2<P1,P2>(thunk_func<Func>, NULL, (PFunc)f, NULL, NULL);
	}

protected:

	template <class Target, class MemFunc>
	static void thunk_member(const FunctorBase &ftor, void* c, P1 p1, P2 p2)
	{
		Target *target = (Target*)c;
		MemFunc &memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
		(target->*memFunc)(p1, p2);
	}

	template <class Func>
	static void thunk_func(const FunctorBase &ftor, void*, P1 p1, P2 p2)
	{
		(Func(ftor.getFunc()))(p1, p2);
	}

	typedef void (*Thunk)(const FunctorBase&, void* target, P1, P2);

	Functor2(Thunk t, const void *c, PFunc f, const void *mf,size_t sz)
		: FunctorBase(c,f,mf,sz),
		  thunk(t)
	{
	}

private:
	Thunk thunk;
};

/************************* two args - with return *******************/
template <class P1, class P2, class RT>
class Functor2wRet : public FunctorBase
{
public:
	typedef P1 Arg1;
	typedef P2 Arg2;

    Functor2wRet() {}

    RT Call(P1 p1, P2 p2) const
    {
        return (thunk(*this, getTarget(), p1, p2));
    }

    RT operator()(P1 p1, P2 p2)const
    {
        return Call(p1, p2);
    }

    // Unsafe
    template<class Target>
    RT Call(Target* t, P1 p1, P2 p2) const
    {
        return (thunk(*this, t, p1, p2));
    }

    //for STL
    typedef P1 first_argument_type;
    typedef P2 second_argument_type;
    typedef RT result_type;

    template <class Target, class MemFunc>
    static Functor2wRet<P1, P2, RT> MakeFunctor(Target* t, const MemFunc& m)
    {
        return Functor2wRet<P1, P2, RT>(thunk_member<Target, MemFunc>,t,0,&m,sizeof(MemFunc));
    }

    template <class Func>
    static Functor2wRet<P1, P2, RT> MakeFunctor(Func f)
    {
        return Functor2wRet<P1, P2, RT>(thunk_func<Func>,0,(PFunc)f,0,0);
    }

protected:

    template <class Target, class MemFunc>
    static RT thunk_member(const FunctorBase &ftor, void* t, P1 p1, P2 p2)
    {
        Target *target = (Target *)t;
        MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
        return ((target->*memFunc)(p1, p2));
    }	

    template <class Func>
    static RT thunk_func(const FunctorBase &ftor, void* t, P1 p1, P2 p2)
    {
        return (Func(ftor.getFunc()))(p1, p2);
    }

    typedef RT (*Thunk)(const FunctorBase &, void* t, P1, P2);

    Functor2wRet(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
        : FunctorBase(c,f,mf,sz),
        thunk(t)
    {
    }

private:
    Thunk thunk;
};

/************************* three args - no return *******************/
template <class P1, class P2, class P3>
class Functor3 : public FunctorBase
{
public:

    Functor3() {}

    void Call(P1 p1, P2 p2, P3 p3) const
    {
        return (thunk(*this, getTarget(), p1, p2, p3));
    }

    void operator()(P1 p1, P2 p2, P3 p3)const
    {
        return Call(p1, p2, p3);
    }

    // Unsafe
    template<class Target>
    void Call(Target* t, P1 p1, P2 p2, P3 p3) const
    {
        return (thunk(*this, t, p1, p2, p3));
    }

    //for STL
    typedef P1 first_argument_type;
    typedef P2 second_argument_type;
    typedef P3 third_argument_type;

    template <class Target, class MemFunc>
    static Functor3<P1, P2, P3> MakeFunctor(Target* t, const MemFunc& m)
    {
        return Functor3<P1, P2, P3>(thunk_member<Target, MemFunc>,t,0,&m,sizeof(MemFunc));
    }

    template <class Func>
    static Functor3<P1, P2, P3> MakeFunctor(Func f)
    {
        return Functor3<P1, P2, P3>(thunk_func<Func>,0,(PFunc)f,0,0);
    }

protected:

    template <class Target, class MemFunc>
    static void thunk_member(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3)
    {
        Target *target = (Target *)t;
        MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
        return ((target->*memFunc)(p1, p2, p3));
    }	

    template <class Func>
    static void thunk_func(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3)
    {
        return (Func(ftor.getFunc()))(p1, p2, p3);
    }

    typedef void (*Thunk)(const FunctorBase &, void* t, P1, P2, P3);

    Functor3(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
        : FunctorBase(c,f,mf,sz),
        thunk(t)
    {
    }

private:
    Thunk thunk;
};

/************************* three args - with return *******************/
template <class P1, class P2, class P3, class RT>
class Functor3wRet : public FunctorBase
{
public:

    Functor3wRet() {}

    RT Call(P1 p1, P2 p2, P3 p3) const
    {
        return (thunk(*this, getTarget(), p1, p2, p3));
    }

    RT operator()(P1 p1, P2 p2, P3 p3)const
    {
        return Call(p1, p2, p3);
    }

    // Unsafe
    template<class Target>
    RT Call(Target* t, P1 p1, P2 p2, P3 p3) const
    {
        return (thunk(*this, t, p1, p2, p3));
    }

    //for STL
    typedef P1 first_argument_type;
    typedef P2 second_argument_type;
    typedef P3 third_argument_type;
    typedef RT result_type;

    template <class Target, class MemFunc>
    static Functor3wRet<P1, P2, P3, RT> MakeFunctor(Target* t, const MemFunc& m)
    {
        return Functor3wRet<P1, P2, P3, RT>(thunk_member<Target, MemFunc>,t,0,&m,sizeof(MemFunc));
    }

    template <class Func>
    static Functor3wRet<P1, P2, P3, RT> MakeFunctor(Func f)
    {
        return Functor3wRet<P1, P2, P3, RT>(thunk_func<Func>,0,(PFunc)f,0,0);
    }

protected:

    template <class Target, class MemFunc>
    static RT thunk_member(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3)
    {
        Target *target = (Target *)t;
        MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
        return ((target->*memFunc)(p1, p2, p3));
    }	

    template <class Func>
    static RT thunk_func(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3)
    {
        return (Func(ftor.getFunc()))(p1, p2, p3);
    }

    typedef RT (*Thunk)(const FunctorBase &, void* t, P1, P2, P3);

    Functor3wRet(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
        : FunctorBase(c,f,mf,sz),
        thunk(t)
    {
    }

private:
    Thunk thunk;
};

/************************* four args - no return *******************/
template <class P1, class P2, class P3, class P4>
class Functor4 : public FunctorBase
{
public:

    Functor4() {}

    void Call(P1 p1, P2 p2, P3 p3, P4 p4) const
    {
        return (thunk(*this, getTarget(), p1, p2, p3, p4));
    }

    void operator()(P1 p1, P2 p2, P3 p3, P4 p4)const
    {
        return Call(p1, p2, p3, p4);
    }

    // Unsafe
    template<class Target>
    void Call(Target* t, P1 p1, P2 p2, P3 p3, P4 p4) const
    {
        return (thunk(*this, t, p1, p2, p3, p4));
    }

    //for STL
    typedef P1 first_argument_type;
    typedef P2 second_argument_type;
    typedef P3 third_argument_type;
    typedef P4 fourth_argument_type;

    template <class Target, class MemFunc>
    static Functor4<P1, P2, P3, P4> MakeFunctor(Target* t, const MemFunc& m)
    {
        return Functor4<P1, P2, P3, P4>(thunk_member<Target, MemFunc>,t,0,&m,sizeof(MemFunc));
    }

    template <class Func>
    static Functor4<P1, P2, P3, P4> MakeFunctor(Func f)
    {
        return Functor4<P1, P2, P3, P4>(thunk_func<Func>,0,(PFunc)f,0,0);
    }

protected:

    template <class Target, class MemFunc>
    static void thunk_member(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3, P4 p4)
    {
        Target *target = (Target *)t;
        MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
        return ((target->*memFunc)(p1, p2, p3, p4));
    }	

    template <class Func>
    static void thunk_func(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3, P4 p4)
    {
        return (Func(ftor.getFunc()))(p1, p2, p3, p4);
    }

    typedef void (*Thunk)(const FunctorBase &, void* t, P1, P2, P3, P4);

    Functor4(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
        : FunctorBase(c,f,mf,sz),
        thunk(t)
    {
    }

private:
    Thunk thunk;
};

/************************* four args - with return *******************/
template <class P1, class P2, class P3, class P4, class RT>
class Functor4wRet : public FunctorBase
{
public:

	Functor4wRet() {}

	RT Call(P1 p1, P2 p2, P3 p3, P4 p4) const
	{
		return (thunk(*this, getTarget(), p1, p2, p3, p4));
	}

	RT operator()(P1 p1, P2 p2, P3 p3, P4 p4)const
	{
		return Call(p1, p2, p3, p4);
	}

	// Unsafe
	template<class Target>
	RT Call(Target* t, P1 p1, P2 p2, P3 p3, P4 p4) const
	{
		return (thunk(*this, t, p1, p2, p3, p4));
	}

	//for STL
	typedef P1 first_argument_type;
    typedef P2 second_argument_type;
    typedef P3 third_argument_type;
    typedef P4 fourth_argument_type;
	typedef RT result_type;

	template <class Target, class MemFunc>
	static Functor4wRet<P1, P2, P3, P4, RT> MakeFunctor(Target* c, const MemFunc& m)
	{
		return Functor4wRet<P1,P2,P3,P4,RT>(thunk_member<Target, MemFunc>,c,0,&m,sizeof(MemFunc));
	}

	template <class Func>
	static Functor4wRet<P1, P2, P3, P4, RT> MakeFunctor(Func f)
	{
		return Functor4wRet<P1,P2,P3,P4,RT>(thunk_func<Func>,0,(PFunc)f,0,0);
	}

protected:

	template <class Target, class MemFunc>
	static RT thunk_member(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3, P4 p4)
	{
		Target *target = (Target *)t;
		MemFunc& memFunc = (*(MemFunc*)(void *)(ftor.getMemFunc()));
		return ((target->*memFunc)(p1, p2, p3, p4));
	}	

	template <class Func>
	static RT thunk_func(const FunctorBase &ftor, void* t, P1 p1, P2 p2, P3 p3, P4 p4)
	{
		return (Func(ftor.getFunc()))(p1, p2, p3, p4);
	}
	
	typedef RT (*Thunk)(const FunctorBase &, void* t, P1, P2, P3, P4);

	Functor4wRet(Thunk t,const void *c,PFunc f,const void *mf,size_t sz)
		: FunctorBase(c,f,mf,sz),
		  thunk(t)
	{
	}

private:
	Thunk thunk;
};

} //namespace core
} //namespace tt

#endif //_protection_ORBITFUNCTORS_H_

